#!/usr/bin/env python3
# -*- coding: utf-8 -*-

# 把新增内置函数，新增系统目录，新增函数，修改文件都以表格的方式列出来
import os
import re
import sys
from docx import Document
from docx.shared import Pt, Cm, RGBColor
from docx.enum.text import WD_ALIGN_PARAGRAPH
from docx.oxml.ns import qn
# 导入处理XML所需的模块
from docx.oxml.ns import nsdecls

def parse_patch_file(patch_file):
    """解析单个patch文件，提取相关信息"""
    with open(patch_file, 'r', encoding='utf-8', errors='replace') as f:
        content = f.read()
    
    # 提取修改文件列表
    modified_files = []
    file_pattern = re.compile(r'diff --git a/(.*?) b/')
    for match in file_pattern.finditer(content):
        modified_files.append(match.group(1))
    
    # 从内容中提取内置函数、系统目录和普通函数
    builtin_funcs = extract_builtin_functions(content)
    system_catalogs = extract_system_catalogs(content)
    functions_with_params = extract_functions_with_params(content)
    
    # 提取函数名列表，移除内置函数中已经在functions中的函数
    functions = [f['name'] for f in functions_with_params if f['name'] not in builtin_funcs]
    
    return {
        'modified_files': modified_files,
        'builtin_funcs': builtin_funcs,
        'system_catalogs': system_catalogs,
        'functions': functions,
        'functions_with_params': functions_with_params
    }

def extract_builtin_functions(content):
    """从patch内容中提取新增的内置函数（只在builtin_funcs.ini文件中新增的行）"""
    builtin_funcs = []
    
    # 分割内容找到builtin_funcs.ini文件的部分
    sections = re.split(r'diff --git', content)
    for section in sections:
        if 'builtin_funcs.ini' in section:
            # 找到builtin_funcs.ini文件的修改部分
            lines = section.split('\n')
            in_diff = False
            for line in lines:
                # 只处理以+开头的行（新增行）
                if line.startswith('+') and not line.startswith('+++'):
                    # 查找AddFuncGroup模式 
                    if 'AddFuncGroup' in line:
                        match = re.search(r'AddFuncGroup\(\s*"([^"]+)"', line)
                        if match and match.group(1) not in builtin_funcs:
                            builtin_funcs.append(match.group(1))
                    
                    # 查找函数名定义模式 例如：+        "pw_global_cursor_info", 1,
                    else:
                        match = re.search(r'\+\s+"([a-zA-Z0-9_]+)"\s*,\s*\d+\s*,', line)
                        if match and match.group(1) not in builtin_funcs:
                            builtin_funcs.append(match.group(1))
    
    return builtin_funcs

def extract_system_catalogs(content):
    """从patch内容中提取系统目录（系统表），去掉.h后缀"""
    system_catalogs = []
    
    # 查找新建的系统目录文件
    catalog_pattern = re.compile(r'create mode \d+ src/include/catalog/(pg_[a-zA-Z0-9_]+)\.h')
    for match in catalog_pattern.finditer(content):
        catalog = match.group(1)  # 直接获取不含.h后缀的目录名
        if catalog not in system_catalogs:
            system_catalogs.append(catalog)
    
    return system_catalogs

def parse_function_parameters(param_string):
    """解析函数参数字符串，返回参数列表"""
    if not param_string or param_string.strip() == 'void' or param_string.strip() == '':
        return []
    
    # 处理PG_FUNCTION_ARGS的情况
    if 'PG_FUNCTION_ARGS' in param_string:
        return [{'type': 'PG_FUNCTION_ARGS', 'name': ''}]
    
    params = []
    # 分割参数，考虑到可能有嵌套的括号或逗号
    param_parts = []
    current_param = ''
    paren_count = 0
    
    for char in param_string:
        if char == '(' :
            paren_count += 1
        elif char == ')':
            paren_count -= 1
        elif char == ',' and paren_count == 0:
            param_parts.append(current_param.strip())
            current_param = ''
            continue
        current_param += char
    
    if current_param.strip():
        param_parts.append(current_param.strip())
    
    for param in param_parts:
        param = param.strip()
        if not param:
            continue
            
        # 移除static等修饰符，但保留const因为它是类型的一部分
        param = re.sub(r'\b(static|volatile|register|inline)\b\s*', '', param)
        
        # 处理默认值：移除 = default_value 部分
        if '=' in param:
            param = param.split('=')[0].strip()
        
        # 处理指针和数组
        # 匹配各种参数格式: type name, type *name, type **name, type name[], 等
        match = re.match(r'(.+?)\s*(\**)([a-zA-Z_][a-zA-Z0-9_]*)\s*(\[.*?\])?$', param)
        if match:
            param_type = match.group(1).strip()
            pointers = match.group(2)
            param_name = match.group(3)
            array_part = match.group(4) or ''
            
            # 构建完整的类型
            full_type = param_type + pointers + array_part
            params.append({'type': full_type.strip(), 'name': param_name})
        else:
            # 如果无法解析，至少保存原始字符串
            params.append({'type': param.strip(), 'name': ''})
    
    return params

def extract_functions_with_params(content):
    """从patch内容中提取新增的普通函数及其参数信息 - 基于原有正确逻辑"""
    functions = []
    
    # 将内容按行分割
    lines = content.split('\n')
    
    # 查找以+开头的行，提取其中的函数定义
    func_lines = []
    for line in lines:
        if line.startswith('+') and not line.startswith('+++'):
            func_lines.append(line[1:])  # 去掉开头的+号
    
    # 将所有以+开头的行合并成一个字符串，用于分析函数定义
    func_content = '\n'.join(func_lines)
    
    # 多种函数定义模式：
    
    # 1. 标准C/C++函数：返回类型 函数名(参数...) {
    standard_func_pattern = re.compile(r'(static\s+)?(inline\s+)?([a-zA-Z0-9_]+\s+)([a-zA-Z0-9_]+)\s*\(([^)]*)\)\s*\{', re.MULTILINE)
    for match in standard_func_pattern.finditer(func_content):
        func_name = match.group(4)
        param_string = match.group(5)
        
        # 过滤掉控制结构关键字和系统宏
        func_names = [f['name'] for f in functions]
        if (func_name not in func_names and 
            not func_name.startswith('if') and 
            not func_name.startswith('for') and 
            not func_name.startswith('while') and 
            not func_name.startswith('switch') and
            not func_name.upper() == func_name):  # 全大写通常是宏
            
            params = parse_function_parameters(param_string)
            functions.append({
                'name': func_name,
                'params': params
            })
    
    # 2. PG_FUNCTION_ARGS格式：Datum 函数名(PG_FUNCTION_ARGS)
    pg_func_pattern = re.compile(r'Datum\s+([a-zA-Z0-9_]+)\s*\(\s*PG_FUNCTION_ARGS\s*\)')
    for match in pg_func_pattern.finditer(func_content):
        func_name = match.group(1)
        func_names = [f['name'] for f in functions]
        if func_name not in func_names:
            params = [{'type': 'PG_FUNCTION_ARGS', 'name': ''}]
            functions.append({
                'name': func_name,
                'params': params
            })
    
    # 3. 常见函数原型声明，但是确保它不是函数调用：返回类型 函数名(参数...);
    # 确保前面有返回类型，后面有分号，并且在同一行内
    proto_func_pattern = re.compile(r'(?<!\S)([a-zA-Z0-9_]+)\s+([a-zA-Z0-9_]+)\s*\(([^)]*)\)\s*;', re.MULTILINE)
    for match in proto_func_pattern.finditer(func_content):
        return_type = match.group(1)
        func_name = match.group(2)
        param_string = match.group(3)
        
        # 过滤掉常见的宏、控制结构和不是真正函数的内容
        func_names = [f['name'] for f in functions]
        if (func_name not in func_names and 
            not func_name.startswith('if') and 
            not func_name.startswith('for') and 
            not func_name.startswith('while') and 
            not func_name.startswith('switch') and
            not func_name.upper() == func_name and  # 全大写通常是宏
            return_type not in ['if', 'for', 'while', 'switch', 'else']):
            
            params = parse_function_parameters(param_string)
            functions.append({
                'name': func_name,
                'params': params
            })
    
    # 排除常见的宏和函数调用模式
    exclude_patterns = [
        r'COPY_[A-Z_]+',    # 如COPY_SCALAR_FIELD
        r'COMPARE_[A-Z_]+', # 如COMPARE_STRING_FIELD
        r'#define',         # 宏定义
        r'[A-Z_]{3,}',      # 全大写且长度大于3的通常是宏
    ]
    
    # 根据排除模式过滤函数列表
    filtered_functions = []
    for func_info in functions:
        func_name = func_info['name']
        exclude = False
        for pattern in exclude_patterns:
            if re.match(pattern, func_name):
                exclude = True
                break
        if not exclude:
            filtered_functions.append(func_info)
    
    return filtered_functions

def extract_functions(content):
    """从patch内容中提取新增的普通函数（各种格式的函数定义）"""
    functions = []
    
    # 将内容按行分割
    lines = content.split('\n')
    
    # 查找以+开头的行，提取其中的函数定义
    func_lines = []
    for line in lines:
        if line.startswith('+') and not line.startswith('+++'):
            func_lines.append(line[1:])  # 去掉开头的+号
    
    # 将所有以+开头的行合并成一个字符串，用于分析函数定义
    func_content = '\n'.join(func_lines)
    
    # 多种函数定义模式：
    
    # 1. 标准C/C++函数：返回类型 函数名(参数...) {
    standard_func_pattern = re.compile(r'(static\s+)?(inline\s+)?([a-zA-Z0-9_]+\s+)([a-zA-Z0-9_]+)\s*\([^)]*\)\s*\{', re.MULTILINE)
    for match in standard_func_pattern.finditer(func_content):
        func_name = match.group(4)
        # 过滤掉控制结构关键字和系统宏
        if (func_name not in functions and 
            not func_name.startswith('if') and 
            not func_name.startswith('for') and 
            not func_name.startswith('while') and 
            not func_name.startswith('switch') and
            not func_name.upper() == func_name):  # 全大写通常是宏
            functions.append(func_name)
    
    # 2. PG_FUNCTION_ARGS格式：Datum 函数名(PG_FUNCTION_ARGS)
    pg_func_pattern = re.compile(r'Datum\s+([a-zA-Z0-9_]+)\s*\(\s*PG_FUNCTION_ARGS\s*\)')
    for match in pg_func_pattern.finditer(func_content):
        func_name = match.group(1)
        if func_name not in functions:
            functions.append(func_name)
    
    # 3. 常见函数原型声明，但是确保它不是函数调用：返回类型 函数名(参数...);
    # 确保前面有返回类型，后面有分号，并且在同一行内
    proto_func_pattern = re.compile(r'(?<!\S)([a-zA-Z0-9_]+)\s+([a-zA-Z0-9_]+)\s*\([^)]*\)\s*;', re.MULTILINE)
    for match in proto_func_pattern.finditer(func_content):
        return_type = match.group(1)
        func_name = match.group(2)
        
        # 过滤掉常见的宏、控制结构和不是真正函数的内容
        if (func_name not in functions and 
            not func_name.startswith('if') and 
            not func_name.startswith('for') and 
            not func_name.startswith('while') and 
            not func_name.startswith('switch') and
            not func_name.upper() == func_name and  # 全大写通常是宏
            return_type not in ['if', 'for', 'while', 'switch', 'else']):
            functions.append(func_name)
    
    # 排除常见的宏和函数调用模式
    exclude_patterns = [
        r'COPY_[A-Z_]+',    # 如COPY_SCALAR_FIELD
        r'COMPARE_[A-Z_]+', # 如COMPARE_STRING_FIELD
        r'#define',         # 宏定义
        r'[A-Z_]{3,}',      # 全大写且长度大于3的通常是宏
    ]
    
    # 根据排除模式过滤函数列表
    filtered_functions = []
    for func in functions:
        exclude = False
        for pattern in exclude_patterns:
            if re.match(pattern, func):
                exclude = True
                break
        if not exclude:
            filtered_functions.append(func)
    
    return filtered_functions

def print_table(title, headers, rows):
    """以表格形式打印数据"""
    # 计算每列的最大宽度
    col_widths = [len(h) for h in headers]
    
    if not rows:
        rows = [("无", "")]
    
    for row in rows:
        for i, cell in enumerate(row):
            col_widths[i] = max(col_widths[i], len(str(cell)))
    
    # 表格顶部
    separator = '+' + '+'.join('-' * (width + 2) for width in col_widths) + '+'
    print(f"\n{title}")
    print(separator)
    
    # 表头
    header_row = '|' + '|'.join(f' {h:{col_widths[i]}} ' for i, h in enumerate(headers)) + '|'
    print(header_row)
    print(separator)
    
    # 数据行
    for row in rows:
        data_row = '|' + '|'.join(f' {str(cell):{col_widths[i]}} ' for i, cell in enumerate(row)) + '|'
        print(data_row)
    
    # 表格底部
    print(separator)

def apply_cell_formatting(cell, is_header=False):
    """应用单元格格式：中文宋体，英文Times New Roman"""
    # 应用字体设置
    for paragraph in cell.paragraphs:
        for run in paragraph.runs:
            # 设置英文字体为Times New Roman
            run.font.name = 'Times New Roman'
            # 设置中文字体为宋体
            run._element.rPr.rFonts.set(qn('w:eastAsia'), '宋体')
            
            if is_header:
                # 表头文字加粗
                run.bold = True

def parse_xml(xml_string):
    """解析XML字符串"""
    from lxml import etree
    return etree.fromstring(xml_string)

def create_table_with_style(doc, title, headers, data):
    """创建带样式的表格"""
    # 添加标题
    heading = doc.add_heading(title, level=1)
    # 设置标题字体为宋体
    for run in heading.runs:
        run.font.name = 'Times New Roman'
        run._element.rPr.rFonts.set(qn('w:eastAsia'), '宋体')
    
    # 如果没有数据，创建只有"无"的表格
    if not data:
        data = [("无", "")]
    
    # 创建表格
    table = doc.add_table(rows=1, cols=len(headers))
    table.style = 'Table Grid'
    
    # 设置表头
    header_row = table.rows[0]
    for i, header in enumerate(headers):
        cell = header_row.cells[i]
        cell.text = header
        # 设置表头背景色为浅蓝色 (RGB: 189, 215, 238)
        shading_elm = parse_xml(r'<w:shd {} w:fill="BDD7EE"/>'.format(nsdecls('w')))
        cell._tc.get_or_add_tcPr().append(shading_elm)
        # 应用字体格式
        apply_cell_formatting(cell, is_header=True)
    
    # 添加数据行
    for item in data:
        row_cells = table.add_row().cells
        for i, value in enumerate(item):
            row_cells[i].text = str(value)
            # 应用字体格式
            apply_cell_formatting(row_cells[i])
    
    return table

def create_function_parameter_table(doc, func_name, params):
    """为单个函数创建参数表格"""
    # 添加函数名作为标题
    heading = doc.add_heading(func_name, level=2)
    # 设置标题字体为宋体
    for run in heading.runs:
        run.font.name = 'Times New Roman'
        run._element.rPr.rFonts.set(qn('w:eastAsia'), '宋体')
    
    # 处理不同类型的参数情况
    if not params:
        # 无参数函数
        data = [("无参数", "", "", "")]
    elif len(params) == 1 and params[0]['type'] == 'PG_FUNCTION_ARGS':
        # PG_FUNCTION_ARGS格式的函数
        data = [("PG_FUNCTION_ARGS", "PG_FUNCTION_ARGS", "", "")]
    else:
        # 普通参数函数
        data = []
        for param in params:
            param_name = param['name'] if param['name'] else "未知参数"
            param_type = param['type'] if param['type'] else "未知类型"
            data.append((param_name, param_type, "", ""))
    
    # 创建表格
    headers = ["参数名称", "参数类型", "入参出参", "参数描述"]
    table = doc.add_table(rows=1, cols=len(headers))
    table.style = 'Table Grid'
    
    # 设置表头
    header_row = table.rows[0]
    for i, header in enumerate(headers):
        cell = header_row.cells[i]
        cell.text = header
        # 设置表头背景色为浅蓝色 (RGB: 189, 215, 238)
        shading_elm = parse_xml(r'<w:shd {} w:fill="BDD7EE"/>'.format(nsdecls('w')))
        cell._tc.get_or_add_tcPr().append(shading_elm)
        # 应用字体格式
        apply_cell_formatting(cell, is_header=True)
    
    # 添加数据行
    for item in data:
        row_cells = table.add_row().cells
        for i, value in enumerate(item):
            row_cells[i].text = str(value)
            # 应用字体格式
            apply_cell_formatting(row_cells[i])
    
    return table

def create_word_document(patch_file, results):
    """创建Word文档并添加表格"""
    doc = Document()
    
    # 设置文档标题
    patch_name = os.path.basename(patch_file)
    title = doc.add_paragraph(f"{patch_name} 分析结果")
    title_format = title.paragraph_format
    title_format.alignment = WD_ALIGN_PARAGRAPH.CENTER
    title_run = title.runs[0]
    title_run.bold = True
    title_run.font.size = Pt(16)
    # 设置中英文字体
    title_run.font.name = 'Times New Roman'
    title_run._element.rPr.rFonts.set(qn('w:eastAsia'), '宋体')
    
    # 添加各类表格
    create_table_with_style(doc, "新增内置函数", ["函数名", "修改描述"], 
                           [(func, "") for func in results['builtin_funcs']])
    
    create_table_with_style(doc, "新增系统目录", ["目录名", "修改描述"], 
                           [(catalog, "") for catalog in results['system_catalogs']])
    
    create_table_with_style(doc, "新增函数", ["函数名", "修改描述"], 
                           [(func, "") for func in results['functions']])
    
    create_table_with_style(doc, "修改文件", ["文件路径", "修改描述"], 
                           [(file, "") for file in results['modified_files']])
    
    # 为每个函数创建参数表格
    if results['functions_with_params']:
        # 添加函数参数部分的标题
        func_params_heading = doc.add_heading("函数参数详情", level=1)
        for run in func_params_heading.runs:
            run.font.name = 'Times New Roman'
            run._element.rPr.rFonts.set(qn('w:eastAsia'), '宋体')
        
        # 为每个函数创建参数表格
        for func_info in results['functions_with_params']:
            # 只为不在内置函数中的函数创建参数表格
            if func_info['name'] not in results['builtin_funcs']:
                create_function_parameter_table(doc, func_info['name'], func_info['params'])
    
    # 保存文档，添加时间戳避免文件被占用
    import datetime
    timestamp = datetime.datetime.now().strftime("%Y%m%d_%H%M%S")
    base_name = os.path.splitext(patch_name)[0]
    doc_name = f"{base_name}_分析结果_{timestamp}.docx"
    
    # 尝试保存文档
    try:
        doc.save(doc_name)
    except PermissionError:
        # 如果文件被占用，生成新的文件名再试一次
        import random
        random_suffix = random.randint(1000, 9999)
        doc_name = f"{base_name}_分析结果_{timestamp}_{random_suffix}.docx"
        doc.save(doc_name)
    
    return doc_name

def main():
    # 检查是否有命令行参数
    if len(sys.argv) > 1:
        # 使用指定的patch文件
        patch_file = sys.argv[1]
    else:
        print("错误: 未指定patch文件")
        print("用法: python parse_patches.py <patch文件名>")
        return
    
    if not os.path.exists(patch_file):
        print(f"错误: 文件 {patch_file} 不存在")
        return
        
    print(f"正在解析: {patch_file}")
    results = parse_patch_file(patch_file)
    
    # 创建Word文档
    doc_name = create_word_document(patch_file, results)
    print(f"分析结果已保存到Word文档: {doc_name}")

if __name__ == "__main__":
    main() 